﻿using System.Collections.Generic;
using System.ComponentModel;

namespace eProject.ViewModel.Commands
{
    public class CommandsQueue : INotifyPropertyChanged
    {
        private readonly IList<ICommand> _commands = new List<ICommand>(50);//TODO remove magic number

        private int _pointer = -1;

        private bool _canUndo;

        private bool _canRedo;

        private int _length;

        public int Length
        {
            get { return _length; }
            private set
            {
                if (value == _length) return;
                _length = value;
                InvokePropertyChanged("Length");
            }
        }

        public bool CanUndo
        {
            get { return _canUndo; }
            private set
            {
                if (value == _canUndo) return;
                _canUndo = value;
                InvokePropertyChanged("CanUndo");
            }
        }

        public bool CanRedo
        {
            get { return _canRedo; }
            private set
            {
                if (value == _canRedo) return;
                _canRedo = value;
                InvokePropertyChanged("CanRedo");
            }
        }

        public void Undo()
        {
            if (!CanUndo) return;
            var command = _commands[_pointer--];
            command.Unexecute();
            UpdateProperties();
        }

        public void Redo()
        {
            if (!CanRedo) return;
            var command = _commands[++_pointer];
            command.Execute();
            UpdateProperties();
        }

        public void Do(ICommand command)
        {
            RemoveAllAfterPointer();
            _commands.Add(command);
            _pointer++;
            command.Execute();
            UpdateProperties();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RemoveAllAfterPointer()
        {
            for (var i = _commands.Count-1; i > _pointer; i--)
            {
                _commands.RemoveAt(i);
            }
        }

        private void UpdateProperties()
        {
            CanRedo = _pointer < _commands.Count - 1;
            CanUndo = _pointer > -1;
            Length = _pointer + 1;
        }
        

        private void InvokePropertyChanged(string property)
        {
            PropertyChangedEventHandler changed = PropertyChanged;
            if (changed != null) changed(this, new PropertyChangedEventArgs(property));
        }
    }
}
